/**
 * @class   wosh::Message
 * @brief   WOSH is a SOA, BUS oriended framework. This object allows services
 *          and devices to talk theirselves (locally ad remotely both).
 *          
 *          
 *
 *
 ****************************************************************************
 * @version $Id: Message.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_Message_H__
 #define __WOSH_Core_Message_H__

 #include <woshDefs.h>
 #include <core/Serialization.h>
 #include <core/MessageContent.h>
 #include <core/SecurityToken.h>
 #include <core/DataFields.h>
 #include <core/MessageNetworkForwarding.h>
 #include <core/URI.h>

namespace wosh {

class Bus;
class Object;
class Bundle;
class PropertiesProvider;
class InterfacesProvider;
class Message;
template <class T> class DataFieldCollector;

void message_assign( Message* message, int64 id, int64 ref_id, int64 ts);


class Message :		public ISerializable,
					public IFieldAccessible
 {
	WOSH_SERIALIZABLE(wosh::Message)
	WOSH_COMPARE_RTTI(wosh::Message)

	public:
		/// priorities of a message
		enum PRIORITY {
			PRIORITY_LOWEST		= 0x00,
			PRIORITY_LOW		= 0x01,
			PRIORITY_NORMAL		= 0x02,
			PRIORITY_HIGH		= 0x03,
			PRIORITY_HIGHEST	= 0x04,
			PRIORITY_REALTIME	= 0x05
		};

	public:
		/**
		 * @brief  Empty constructor.
		 */
		Message();
		/**
		 * @brief  Constructor with initializer(s), provided for convenience.
		 * @param [in] Content the content object to be assigned
		 * @param [in] deleteContents free the content on destruction (true by default)
		 */
		explicit Message( MessageContent* Content, bool deleteContents = true );
		/**
		 * @brief  Constructor with initializer(s), provided for convenience.
		 * @param [in] DestinationURI the destination URI as string
		 * @param [in] Content the content object to be assigned
		 * @param [in] deleteContents free the content on destruction (true by default)
		 */
		explicit Message( const std::string& DestinationURI, MessageContent* Content, bool deleteContents = true );
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		Message( const Message& m );
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~Message();


	public:
		/**
		 * @brief  Create a new Message object as Reply to this message. Provided for convenience.
		 * @param [in] newContent set the content of the reply (optional)
		 * @param [in] security_payload the security payload to be assigned to the message 
		 * @return pointer to a new Object
		 * @note   caller must care about freeing memory
		 */
		Message* replyTo( MessageContent* newContent = NULL, SecurityToken* security_payload = NULL ) const;


/** @name Getters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Get the (unique) ID of the message
		 * @return Unique ID of the message as long long integer (int64)
		 */
		inline int64 getID() const								{ return this->id; }

		/**
		 * @brief  Get the (unique) ID of the reference message, may be unset (0). Usually used when answering a message.
		 * @return (unique) ID of the reference message
		 */
		inline int64 getReferenceID() const						{ return this->ref_id; }

		/**
		 * @brief  Get the timestamp of message creation
		 * @return timestamp in epoch format (seconds after 1970)
		 */
		inline int64 getTimestamp() const						{ return this->timestamp; }

		/**
		 * @brief  Get the time-to-live of message
		 * @return TTL in seconds format (0 means disabled/non-applicable)
		 */
		inline unsigned long getTTL() const						{ return this->TTL; }


		/**
		 * @brief  Get the timestamp of message creation
		 * @return UTF format rapresentation of timestamp
		 */
		std::string getTimestampAsString() const;


		/**
		 * @brief  Get the name of source bus (first)
		 * @return name of the source bus (first)
		 */
		inline const std::string& getSourceBus() const			{ return this->sourceBus; }

		/**
		 * @brief  Get the name of current bus (updated by Bus)
		 * @return name of the source current bus (updated by Bus)
		 */
		inline const std::string& getCurrentBus() const			{ return this->currentBus; }

		/**
		 * @brief  Get the name of destination bus (last)
		 * @return name of the destination bus (last)
		 */
		inline const std::string& getDestinationBus() const		{ return this->destinationBus; }

		/**
		 * @brief  Get the URI of sender/creator of the message
		 * @return (constant) URI reference of sender/creator of the message (internal field)
		 */
		inline const URI& getSource() const				{ return this->source; }
		/**
		 * @brief  Get the URI of sender/creator of the message
		 * @return (editable) URI reference of sender/creator of the message (internal field)
		 */
		inline URI& getSource()							{ return this->source; }

		/**
		 * @brief  Get the URI of target/destination of the message
		 * @return (constant) URI reference of target/destination of the message (internal field)
		 */
		inline const URI& getDestination() const			{ return this->destination; }
		/**
		 * @brief  Get the URI of target/destination of the message
		 * @return (editable) URI reference of target/destination of the message (internal field)
		 */
		inline URI& getDestination()						{ return this->destination; }

		/**
		 * @brief  Get the name of the source kernel.
		 * @return name of the source kernel
		 */
		inline const std::string& getSourceKernel() const		{ return this->source.getKernelName(); }
		/**
		 * @brief  Get the name of the destination kernel. May be a pattern.
		 * @return name of the destination kernel
		 */
		inline const std::string& getDestinationKernel() const	{ return this->destination.getKernelName(); }

		/**
		 * @brief  Get the UUID string of sender/creator of the message. Usually not set/used.
		 * @return (constant) string containing the UUID of sender/creator of the message (internal field)
		 */
		inline const std::string& getSourceUUID() const			{ return this->sourceUUID; }
		/**
		 * @brief  Get the UUID string of sender/creator of the message. Usually not set/used.
		 * @return (editable) string containing the UUID of sender/creator of the message (internal field)
		 */
		inline std::string& getSourceUUID()						{ return this->sourceUUID; }

		/**
		 * @brief  Get the UUID string of target/destination of the message. Usually not set/used.
		 * @return (constant) string containing the UUID of target/destination of the message (internal field)
		 */
		inline const std::string& getDestinationUUID() const	{ return this->destinationUUID; }
		/**
		 * @brief  Get the UUID string of target/destination of the message. Usually not set/used.
		 * @return (editable) string containing the UUID of target/destination of the message (internal field)
		 */
		inline std::string& getDestinationUUID()				{ return this->destinationUUID; }

		/**
		 * @brief  Evaluates if message is empty (no content)
		 * @return true when content is empty (NULL), false else.
		 */
		inline bool isEmpty() const								{ return ( this->content == NULL ); }

		/**
		 * @brief  Get the pointer to (constant object) content of the message.
		 * @return pointer to constant MessageContent object (internal field)
		 */
		const inline MessageContent* getContent() const 	{ return this->content; }
		/**
		 * @brief  Get the pointer to (editable object) content of the message.
		 * @return pointer to editable MessageContent object (internal field)
		 */
		virtual MessageContent* getContent()				{ return this->content; }

		/**
		 * @brief  Get the classname of the content object. Provided for convenience.
		 * @return STL string containing class-name of the content object, empty string when NULL.
		 * @see    MessageContent::getClassName()
		 */
		inline std::string getContentClassName() const {
			if ( this->content == NULL )
				return "";
			return this->content->getClassName();
		 }

		/**
		 * @brief  Evaluates if message has a security token
		 * @return false when security token is empty (NULL), true else.
		 */
		inline bool hasSecurityToken() const					{ return ( this->security != NULL ); }

		/**
		 * @brief  Get the pointer to (constant object) security token of the message.
		 * @return pointer to constant SecurityToken object (internal field)
		 */
		inline const SecurityToken* getSecurityToken() const	{ return this->security; }
		/**
		 * @brief  Evaluates if message has a forwarders token
		 * @return false when forwarders payload is empty (NULL), true else.
		 */
		inline bool hasNetworkForwarders() const				{ return ( this->forwarders != NULL ); }

		/**
		 * @brief  Get the pointer to (constant object) forwarders payload of the message.
		 * @return pointer to constant MessageNeworkForwarding object (internal field)
		 */
		inline const MessageNetworkForwarding* getNetworkForwarders() const { return this->forwarders; }
		/**
		 * @brief  Get the pointer to (editable object) forwarders payload of the message.
		 * @return pointer to editable MessageNeworkForwarding object (internal field)
		 */
		virtual MessageNetworkForwarding* getNetworkForwarders() { return this->forwarders; }


		/**
		 * @brief  Get the priority of the message.
		 * @return the priority of the message
		 */
		inline PRIORITY getPriority() const						{ return this->priority; }

		/**
		 * @brief  Get the number of acknowledgement.
		 * @return number of acknowledgement
		 */
		inline unsigned int getAcknowledged() const				{ return this->acknowledged; }


		static DataFieldCollector<Message>* getDataFields();

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Get the (unique) ID of the reference message, may be unset (0). Usually used when answering a message.
		 * @param value [in] (unique) ID of the reference message
		 */
		inline void setReferenceID( int64 value )				{ this->ref_id = value; }

		/**
		 * @brief  Set the Source URI and source object's pointer. Provided for convenience.
		 * @param value [in] the pointer of sender/creator object
		 */
		void setSource( const Object* value );

		/**
		 * @brief  Set the Source URI
		 * @param value [in] reference to the URI of the sender/creator object
		 */
		inline void setSource( const URI& value )			{ this->source = value; }

		/**
		 * @brief  Set the Destination URI. May be a pattern.
		 * @param value [in] reference to the URI of the target/destination object
		 */
		inline void setDestination( const URI& value )	{ this->destination = value; }

		/**
		 * @brief  Set the Destination URI as Broadcast. Provided for convenience.
		 * @param [in] anyKernel flag indicating if message should be broadcasted also to other hosts (kernels)
		 */
		void setDestinationBroadcast( bool anyKernel = true );

		/**
		 * @brief  Set the UUID of sender/creator object. Usually not set/used.
		 * @param uuid [in] the UUID of sender/creator object
		 */
		inline void setSourceUUID( const std::string& uuid )	{ this->sourceUUID = uuid; }
		/**
		 * @brief  Set the UUID of target/destination object. Usually not set/used.
		 * @param uuid [in] the UUID of target/destination object
		 */
		inline void setDestinationUUID( const std::string& uuid ) { this->destinationUUID = uuid; }

		/**
		 * @brief  Set the name of the source Kernel
		 * @param kernel_name [in] name of source kernel
		 */
		inline void setSourceKernel( const std::string& kernel_name ) { this->source.setKernelName(kernel_name); }

		/**
		 * @brief  Set the name of the destination Kernel
		 * @param kernel_name [in] name of destination kernel, may be a pattern.
		 */
		inline void setDestinationKernel( const std::string& kernel_name ) { this->destination.setKernelName(kernel_name); }

		/**
		 * @brief  Set the name of the source bus
		 * @param bus_name [in] name of source bus
		 */
		inline void setSourceBus( const std::string& bus_name )		{ this->sourceBus = bus_name; }
		/**
		 * @brief  Set the name of the destination bus
		 * @param bus_name [in] name of destination bus
		 */
		inline void setDestinationBus( const std::string& bus_name ) { this->destinationBus = bus_name; }


		/**
		 * @brief  Set the content of the message. Object won't be copied!
		 * @param content [in] pointer to the content object
		 * @param deleteContents [in] flag indicating to free the object instance when destroying message
		 */
		void setContent( MessageContent* content, bool deleteContents = true );
		/**
		 * @brief  Teel the message to free (or not) the content when destroying message
		 * @param deleteContents [in] flag indicating to free the object instance when destroying message
		 */
		inline void setContentFree( bool deleteContents = true )	{ this->contentDelete = deleteContents; }


		/**
		 * @brief  Set the security token of the message. Object won't be copied!
		 * @param security [in] pointer to the SecurityToken object
		 * @note   previous instance (if any) is released
		 */
		void setSecurityToken( SecurityToken* security );

		/**
		 * @brief  Set the forwarders payload of the message. Object won't be copied!
		 * @param forwarders_hosts [in] pointer to the forwarders payload object
		 * @warning previous instance (if any) won't be released
		 */
		inline void setNetworkForwarders( MessageNetworkForwarding* forwarders_hosts )
																{ this->forwarders = forwarders_hosts; }


		/**
		 * @brief  Set the message as Acknowledged. Incremental set.
		 */
		inline void setAcknowledged() const						{ ++this->acknowledged; }

		/**
		 * @brief  Set time-to-live value in seconds
		 * @param value [in] TTL in seconds format (0 means disabled/non-applicable)
		 */
		inline void setTTL( unsigned long value )				{ this->TTL = value; }

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual Message& operator=(const Message& m);
		virtual bool operator==(const Message &other) const;
		virtual bool operator!=(const Message &other) const { return !(*this == other);  }

//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
/** @name FieldAccessible Interface
 * @{
 ******************************************************************************/
	public:
		virtual WRESULT listFields( std::vector<std::string>& fields_name, const char* parent_field_name = NULL, const SecurityToken* token = NULL );
		virtual WRESULT getField( const char* field_name, ISerializable* value, const SecurityToken* token = NULL );
		virtual WRESULT setField( const char* field_name, const ISerializable* value, const SecurityToken* token = NULL );
		virtual ISerializable* createObjectForField( const char* field_name, const SecurityToken* token = NULL );
//@}
/** @name Internal methods
 * @{
 ******************************************************************************/
	protected:
		virtual void clear();
		virtual void freeContent();

		friend class wosh::Bus;				///< my dear big bro
		friend void message_assign( Message* message, int64 id, int64 ref_id, int64 ts );
//@}
/** @name Internal vars
 * @{
 ******************************************************************************/
	protected:
		int64 id;							///< UID
		int64 ref_id;						///< reference UID, for multi-message and responses

		int64 timestamp;					///< timestamp (epoch) of message creation
		unsigned long TTL;					///< time-to-live in seconds, 0=not applicable

		PRIORITY priority;					///< priority of the message
		mutable unsigned int acknowledged;	///< acknowledgement flag

		std::string sourceBus;				///< name of the source bus (first)
		std::string currentBus;				///< name of the current bus (updated by Bus)
		std::string destinationBus;			///< name of the destination bus (last)

		URI source;							///< URI of the message's creator/sender
		URI destination;					///< URI of the message's target/destination

		std::string sourceUUID;				///< often empty, rapresent UUID of the source
		std::string destinationUUID;		///< often NULL, rapresent UUID of the destionation

		mutable MessageContent* content;	///< content of the message
		bool contentDelete;					///< flag indicating to free content when detroying message

		SecurityToken* security;			///< security token of the message

		MessageNetworkForwarding* forwarders; ///< forwarder (ordered) list of hostname(s)

//@}


}; // class def

}; // namespace wosh

#endif //__WOSH_Core_Message_H__
